#pragma once

struct EMaterialBindFlag
{
	enum Flag
	{
	    NothingChanged			= 0,
	    ChangeTechnique			= 1 << 0,
	    ChangeMaterial			= 1 << 1,
	    ChangeContext			= 1 << 2,
	    ChangeProgram			= 1 << 3,
	    ChangeAll				= ChangeMaterial | ChangeTechnique | ChangeContext | ChangeProgram
	};
};

/*--------------------------------------------------------------------------*/

class CMaterial final :
	public IEngMod
{
public:
	CMaterial();
	~CMaterial();

	/*--------Context is subpart of material------------------------------------*/

	Context*				CreateNewContext(const std::string& name);
	const Context*			GetContext(const std::string& name) const;

	/*--------Material----------------------------------------------------------*/

	void					BindMaterial(const Material* rm, EMaterialTechnique::Type technique);
	const Material*			GetBoundMaterial() const;
	EMaterialTechnique::Type GetBoundTechnique() const;

	void					RegisterMaterial(const std::string& name, Material* material);
	const Material*			GetMaterial(const std::string& name) const;
	const MaterialPtnMap&	GetMaterials() const;

	/*----------------Loading materials-----------------------------------------*/

	void					LoadMaterials(const std::string& file);

	/*--------------------------------------------------------------------------*/

	void					SetMaterialProperties(const glm::vec3* diffuse, const float* shininess, const float* normalMapping);
	void					SetLightProperties(const glm::vec3* position, const glm::vec3* diffuse, float* specular, const float* radius, const float* angleCos, const glm::vec3* direction);

private:
	/*------Uniform buffers-----------------------------------------------------*/
	GLUniformBuffer*		ubo_material;
	GLUniformBuffer*		ubo_light;

	/*-------Containers---------------------------------------------------------*/
	ContextPtnMap			m_contexts;
	MaterialPtnMap			m_materials;

	/*---------Bound structures-------------------------------------------------*/
	const Material*				m_boundMaterial;
	EMaterialTechnique::Type	m_boundTechnique;

	const Context*				m_currentContext;
	const Technique*			m_currentTechnique;
	const GLProgram*			m_currentProgram;

	void Bind_BindContext();
	void Bind_BindProgram();
	void Bind_Samplers();
	void Bind_MaterialTextures();
	void Bind_MaterialProperties();
};

extern CMaterial* g_Material;

